﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.SessionState;
using System.Data;

namespace thailandProject.Models
{
    public class ErrorLog
    {

        /// <summary>
        /// Gets all Errors in the error database
        /// </summary>
        /// <returns>A List with all Errors stored in the database</returns>
        /// Alex Marcum - 3/2/2013
        public static List<ERROR> getAllErrors()
        {
            ThailandEntities a = new ThailandEntities();
            List<ERROR> errorList = new List<ERROR>();

            try
            {
                var errors = from error in a.ERRORs
                            orderby error.errorTimeStamp
                            select error;
                errorList = errors.ToList();
            }
            catch (Exception ex)
            {
                ErrorLog.logError(ex);
            }

            return errorList;
        }

        /// <summary>
        /// Calculate MD5 Hash of any given input
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string CalculateMD5Hash(string input)
        {
            String result = "";
            try
            {
                // step 1, calculate MD5 hash from input
                System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create();
                byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
                byte[] hash = md5.ComputeHash(inputBytes);

                // step 2, convert byte array to hex string
                System.Text.StringBuilder sb = new System.Text.StringBuilder();
                for (int i = 0; i < hash.Length; i++)
                {
                    sb.Append(hash[i].ToString("X2"));
                }
                result = sb.ToString();
            }
            catch (Exception ex)
            {
                ErrorLog.logError(ex);
            }

            return result;
        }

        /// <summary>
        /// Logs an exception into the ErrorLog table
        /// </summary>
        /// <param name="ex"></param>
        /// <returns>Returns the ErrorID of the logged exception, 
        ///         If there is a problem saving to the database -1 is returned, 
        ///         If there is an un-caught error then -2 is returned,
        ///         If there is an Error adding the additionalInformation to the ERROR Object -4 is returned,
        ///         If there was a problem adding the error to the database a -8 is returned,
        ///         If ex was null then -16 is returned,
        ///         If there were multiple errors throughout this logError function they are combined together 
        ///         like a bitwise operator, for Example if there was a problem adding additionInformation and 
        ///         there was an un-caught error then "-6" would be returned.</returns>
        /// Alex Marcum - 3/2/2013
        [System.Web.Mvc.HttpPost]
        public static int logError(Exception ex, String additionalInformation = "")
        {
            if (ex == null)
            {
                return -16;
            }
            System.Diagnostics.StackFrame stackFrame = new System.Diagnostics.StackFrame(1, true);

            // Initialize all error values
            //Class Name is the Whole path to the Filename
            string fileName = "";
            string functionName = "";
            int line = -1;
            DateTime errorTime = new DateTime();
            String errorText = "";
            String errorCode = "";

            // If there are no errors this stays a 0, otherwise look at the heading above
            int errorResult = 0;
            //DataSet ds = new DataSet();

            try
            {
                // Set All error values
                // All of the internal Try Catches are to make sure that the 
                try
                {
                    fileName = stackFrame.GetFileName();
                }
                catch (Exception /*ex*/)
                {
                    additionalInformation = "Could not get the fileName from the stackFrame, " + additionalInformation;
                }
                try
                {
                    functionName = stackFrame.GetMethod().Name.ToString();
                }
                catch (Exception /*ex*/)
                {
                    additionalInformation = "Could not get the functionName from the stackFrame, " + additionalInformation;
                }
                try
                {
                    line = stackFrame.GetFileLineNumber();
                }
                catch (Exception /*ex*/)
                {
                    additionalInformation = "Could not get the Line Number from the stackFrame, " + additionalInformation;
                }

                // Make sure the live server can do this step
                try
                {
                    string stackTraceText = ex.ToString();
                    string[] splits = System.Text.RegularExpressions.Regex.Split(stackTraceText, ":line ");
                    string lineTmp = splits[splits.Length - 1];
                    line = int.Parse(lineTmp);
                }
                catch (Exception /*ex*/)
                {
                    additionalInformation = "The Line Number listed is an estimate, " + additionalInformation;
                }
                try
                {
                    errorTime = DateTime.Now;  //date time stored in order to be used later in getErrorID method
                }
                catch (Exception /*ex*/)
                {
                    additionalInformation = "The current DateTime DateTime could not be added, " + additionalInformation;
                }
                try
                {
                    Exception tmpEx = ex;
                    do
                    {
                        errorText += tmpEx.Message;
                        tmpEx = tmpEx.InnerException;
                        if (tmpEx != null)
                        {
                            logError(tmpEx, "THIS IS AN INNER EXCEPTION!");
                            additionalInformation = "(CONTAINS an inner exception) " + additionalInformation;
                        }
                    } while (tmpEx != null);
                }
                catch (Exception /*ex*/)
                {
                    try
                    {
                        Exception tmpEx = ex;
                        do
                        {
                            errorText += tmpEx.ToString();
                            tmpEx = tmpEx.InnerException;
                            if (tmpEx != null)
                            {
                                logError(tmpEx, "THIS IS AN INNER EXCEPTION!");
                                additionalInformation = "(CONTAINS an inner exception) " + additionalInformation;
                            }
                        } while (tmpEx != null);
                    }
                    catch (Exception /*ex*/)
                    {
                        additionalInformation = "The errorText could not be added by using ToString(), " + additionalInformation;
                    }
                    additionalInformation = "The errorText could not be added by using Message, " + additionalInformation;
                }

                // The error Code is currently set to the MD5 Hash of the exception message
                //  This can be changed later to include a list of exceptions and related numbers if needed
                string errorCodeTmp = "";

                // Make sure the live server can do this step
                try
                {
                    System.IO.FileInfo temp = new System.IO.FileInfo(fileName);
                    fileName = temp.Name;   // Change filename to only include the individual file
                    errorCodeTmp = temp.Name + " " + functionName + " " + errorText;
                }
                catch (Exception /*ex*/)
                {
                    additionalInformation = "The Error Code for this Error is a generic Code, " + additionalInformation;
                }

                try
                {
                    errorCode = CalculateMD5Hash(errorCodeTmp);
                }
                catch (Exception /*ex*/)
                {
                    additionalInformation = "There is a problem with the MD5 Hash generator, " + additionalInformation;
                }

                // Create ERROR
                ERROR curError = new ERROR();
                try
                {
                    curError.errorFileName = fileName;
                    curError.errorFunctionName = functionName;
                    curError.errorLineNumber = line;
                    curError.errorTimeStamp = errorTime;
                    curError.errorText = errorText;
                    curError.errorCode = errorCode;
                    // Add userID
                    curError.userID = -10;
                }
                catch (Exception /*ex*/)
                {
                    additionalInformation = "Could Not add to the ERROR Object, " + additionalInformation;
                }

                try
                {
                    HttpSessionStateWrapper Session = new HttpSessionStateWrapper(HttpContext.Current.Session);
                    if (Session["user"] != null)
                    {
                        USER curUser = (USER)Session["user"];
                        curError.userID = curUser.userID;
                    }
                }
                catch (Exception /*ex*/)
                {
                    additionalInformation = "Unable to verify That the Session User was able to be retrieved, " + additionalInformation;
                }

                try
                {
                    curError.errorAddInfo = additionalInformation;
                }
                catch (Exception /*ex*/)
                {
                    errorResult -= 4;   // Think of this as a bitwise error logging feature
                }

                int changesSaved = 0;
                try
                {
                    using (ThailandEntities a = new ThailandEntities())
                    {
                        a.ERRORs.AddObject(curError);
                        changesSaved = a.SaveChanges();
                    }
                }
                catch (Exception /*ex*/)
                {
                    // There was a problem Adding the Error object to the database.
                    errorResult -= 8;   // Think of this as a bitwise error logging feature
                }

                if (changesSaved != 1)
                {
                    // The error could not be saved in the database
                    return errorResult - 1; // Return all Errors
                }

                if (errorResult < 0)
                    return errorResult;
                else
                    return curError.errorID;
            }
            catch (Exception /*ex*/)
            {
                // This should redirect to an error page if it got this far, 
                //  This would mean there is something wrong with the database
                //  Check permissions and that the database is set up correctly
                return errorResult - 2;
            }
        }

        /// <summary>
        /// Helper method to get ErrorID of logged exception based on the timestamp
        /// </summary>
        /// <param name="errorTime"></param>
        /// <returns></returns>
        /// Alex Marcum - 3/2/2013
        private static DataSet getErrorID(DateTime errorTime)
        {
            /*String connStr = Connections.connErrorLogStr();
            OleDbConnection conn = new OleDbConnection(connStr);
            DataSet ds = new DataSet();

            try
            {
                String sql = "SELECT [ErrorID], [ErrorCode] FROM ErrorLog WHERE [TimeStamp] = @time;";
                OleDbCommand cmd = new OleDbCommand(sql, conn);
                cmd.Parameters.AddWithValue("@time", errorTime.ToString());

                OleDbDataAdapter adapter = new OleDbDataAdapter(cmd);
                adapter.Fill(ds, "Error");
                //int errorID = Int32.Parse(ds.Tables["Error"].Rows[0]["ErrorID"].ToString());
                return ds;
            }
            catch (Exception /*ex2*//*)
            {
                return ds;
            }
            finally
            {
                conn.Close();
            }*/
            return null;
        }
    }

}